﻿using System;
using System.ComponentModel;
using System.IO;

namespace LFSRecord2.Model.Media
{
    public abstract class MediaBase : INotifyPropertyChanged, IDisposable
    {
        public MediaTypes MediaType { get; protected set; }

        string _filePath;
        public string FilePath
        {
            get { return _filePath; }
            set
            {
                _filePath = value;
                OnPropertyChanged("FilePath");
            }
        }

        MediaFileStatus _fileStatus;
        public MediaFileStatus FileStatus
        {
            get { return _fileStatus; }
            set
            {
                _fileStatus = value;
                OnPropertyChanged("FileStatus");
            }
        }

        string _fileErrorString;
        public string FileErrorString
        {
            get { return _fileErrorString; }
            set
            {
                _fileErrorString = value;
                OnPropertyChanged("FileErrorString");
            }
        }

        long _fileSize;
        public long FileSize
        {
            get { return _fileSize; }
            set
            {
                _fileSize = value;
                OnPropertyChanged("FileSize");
            }
        }

        DateTime _fileMTime;
        public DateTime FileMTime
        {
            get { return _fileMTime; }
            set
            {
                _fileMTime = value;
                OnPropertyChanged("FileMTime");
            }
        }

        public MediaIconTypes IconType { get; set; }

        bool _isSelected = false;
        public bool IsSelected 
        {
            get { return _isSelected; }
            set
            {
                _isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public event EventHandler Disposed;
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                PropertyChanged = null;

                EventHandler handler = this.Disposed;
                if (handler != null)
                {
                    var e = new EventArgs();
                    handler(this, e);
                }
                Disposed = null;
            }
        }

        protected bool loadFile()
        {
            // Load the file
            try
            {
                ImportFile();
                FileStatus = MediaFileStatus.Loaded;
                FileErrorString = "";
            }
            catch (FileNotFoundException)
            {
                FileStatus = MediaFileStatus.NotFound;
                FileErrorString = "File Not Found";
                return false;
            }
            catch (Exception ex)
            {
                FileStatus = MediaFileStatus.NotLoaded;
                FileErrorString = ex.Message;
                return false;
            }
            return true;
        }

        protected void populateFileInfo()
        {
            try
            {
                // Populate filesize and mtime
                FileInfo fi = new FileInfo(FilePath);
                FileSize = fi.Length;
                FileMTime = fi.LastWriteTime;
            }
            catch
            {
                resetFileInfo();
            }
        }

        protected void resetFileInfo()
        {
            FileStatus = MediaFileStatus.None;
            FileSize = 0;
            FileMTime = new DateTime();
        }

        protected abstract void ImportFile();
        public abstract void ReloadFile();
        
        public void RenameFile(string newFilePath)
        {
            if (!Path.IsPathRooted(newFilePath))
                throw new Exception("Relative path provided, where an absolute path is required.");

            try
            {
                if (MediaType == MediaTypes.Audio)
                {
                    MediaAudio ma = (MediaAudio)this;
                    if (ma.AudioStream != null)
                        ma.AudioStream.Dispose();
                }
                File.Move(FilePath, newFilePath);
                FilePath = newFilePath;
                if (MediaType == MediaTypes.Audio)
                {
                    MediaAudio ma = (MediaAudio)this;
                    ma.ReloadFile();
                }
            }
            catch (FileNotFoundException)
            {
                // don't do anything here.
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Import and create a media object, by auto detection.
        /// </summary>
        /// <param name="filePath">The path identifying the file to import.</param>
        /// <returns>A MediaBase object or null if the file could not be imported.</returns>
        public static MediaBase MediaFactory(string filePath)
        {
            // Here we try to import the given file as a media object.
            
            // Replay data media file?
            MediaReplayData mrd = new MediaReplayData(filePath);
            if (mrd.FileStatus == MediaFileStatus.Loaded)
                return mrd;

            // Audio media file?
            MediaAudio ma = new MediaAudio(filePath);
            if (ma.FileStatus == MediaFileStatus.Loaded)
                return ma;

            return null;
        }
    }
}
